package org.bridgen.runtime.inspect;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;

import javax.swing.ComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.event.ListDataListener;

import org.bridgen.runtime.RecoveryAlgorithm;
import org.bridgen.runtime.RecoveryHelper;
import org.bridgen.runtime.RecoveryLexer;
import org.bridgen.runtime.RecoveryHelper.Metrics;
import org.bridgen.runtime.model.SOF;

/**
 * 
 * @author Emma Söderberg <emma add cs.lth.se>
 *
 */

public class InspectorGUI extends JFrame {
	
	private static final long serialVersionUID = 1L;
	
	private final RecoveryTextPanel textPanel;
	private JTabbedPane samplePane;
	private SampleFactory sampleFactory;
	private JComboBox sampleBox;

	private JProgressBar progressBar;
	private JButton nextButton;
	private JLabel statusLabel;

	public InspectorGUI (HashMap<String, RecoveryLexer> lexerHash, String path) {
		setTitle("Recovery");
		sampleFactory = new SampleFactory(lexerHash, path);

		textPanel = new RecoveryTextPanel();

		JPanel panel = new JPanel();
		panel.setLayout(new BorderLayout());
        panel.add(createTextPanels(), BorderLayout.CENTER);
		panel.add(createProgressPanel(), BorderLayout.NORTH);
		panel.add(createStatusPanel(), BorderLayout.SOUTH);
		getContentPane().add(panel);
		if (path != null) boxModel.updateSamples(path);
		pack();
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);
	}

	private JPanel createStatusPanel() {
		textPanel.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				showInfo(e);
			}
			public void mouseReleased(MouseEvent e) {
				showInfo(e);
			}
			private void showInfo(MouseEvent e) {
				showStatusForPoint(e.getPoint());
			}
		});
		JPanel panel = new JPanel();
		statusLabel = new JLabel("Status...");
		panel.add(statusLabel);
		return panel;
	}

	private void showStatusForPoint(Point p) {
		statusLabel.setText(textPanel.getStatusForPoint(p));
	}

	private JScrollPane createTextPanels() {
		JPanel panel = new JPanel();
		JScrollPane scrollPane = new JScrollPane(textPanel); 
		scrollPane.setPreferredSize(new Dimension(600,400));
		samplePane = new JTabbedPane();
		samplePane.addTab("Sample", scrollPane);
        panel.add(samplePane);
		return scrollPane;
	}

	private JButton browseButton;
	
	private JPanel createProgressPanel() {
		JPanel panel = new JPanel();
		panel.add(createSamplePanel());
		browseButton = new JButton("Browse..");
		browseButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				JFileChooser chooser = new JFileChooser();
				chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
			    int returnVal = chooser.showOpenDialog(InspectorGUI.this);
			    if(returnVal == JFileChooser.APPROVE_OPTION) {
			       System.out.println("You chose to open this file: " +
			    		   chooser.getSelectedFile().getAbsolutePath());
			       String dirPath = chooser.getSelectedFile().getAbsolutePath();
			       boxModel.updateSamples(dirPath);
			       sampleBox.updateUI();
			    }
			}
		});
		panel.add(browseButton);

		progressBar = new JProgressBar(STATE_INIT,STATE_OUTPUT);
		progressBar.setValue(STATE_INIT);
		progressBar.setStringPainted(true);
		progressBar.setString("Choose file..");
		panel.add(progressBar);

		nextButton = new  JButton("Next");
		nextButton.setEnabled(false);
		nextButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				nextState();
			}
		});
		panel.add(nextButton);

		return panel;
	}
	
	private BoxModel boxModel;
	
	private class BoxModel implements ComboBoxModel {
		private ArrayList<SampleFactory.Sample> content;
		private Object selected;
		public BoxModel() {
			content = new ArrayList<SampleFactory.Sample>();
			updateSamples(null);
		}
		public void updateSamples(String path) {
			content.clear();
			ArrayList<SampleFactory.Sample> samples = sampleFactory.loadSampleNames(path);
			for (SampleFactory.Sample sample : samples) {
				content.add(sample);
			}
		}
		public Object getSelectedItem() {
			return selected;
		}
		public void setSelectedItem(Object arg0) {
			selected = arg0;
		}
		public void addListDataListener(ListDataListener arg0) {
		}
		public Object getElementAt(int arg0) {
			return content.get(arg0);
		}
		public int getSize() {
			return content.size();
		}
		public void removeListDataListener(ListDataListener arg0) {
		}
	}

	private JPanel createSamplePanel() {
		JPanel panel = new JPanel();
		boxModel = new BoxModel();
		sampleBox = new JComboBox(boxModel);
		sampleBox.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				initState((SampleFactory.Sample)sampleBox.getSelectedItem());
			}
		});
		panel.add(sampleBox);
		return panel;
	}
	
	private static final int STATE_INIT = 0;
	private static final int STATE_LEXER = 1;
	private static final int STATE_LINK = 2;
	private static final int STATE_RECOVER = 3;
	private static final int STATE_OUTPUT = 4;
	private int state = STATE_INIT;

	private void nextState() {
		switch (state) {
			case STATE_INIT:
				if (m == null)
					m = new RecoveryHelper.Metrics();
				m.clear();
				lexerState();
				break;
			case STATE_LEXER:
				linkState();
				RecoveryHelper.collectBBU(sof, m);
				RecoveryHelper.collectBBT(sof.getBridge(), m);
				break;
			case STATE_LINK: 
				recoverState();
				RecoveryHelper.collectBRU(sof, m);
				break;
			case STATE_RECOVER: 
				outputState();
				m.print();
				break;
			case STATE_OUTPUT:
				initState(sample);
				break;
		}
	}
	
	private void initState(SampleFactory.Sample sample) {
		this.sample = sample;
		buf = sampleFactory.getFileContent(sample);
		textPanel.showInitResult(buf.toString());
		state = STATE_INIT;
		progressBar.setValue(state);
		progressBar.setString("File loaded");
		nextButton.setEnabled(true);
	}

	private StringBuffer buf;
	private SampleFactory.Sample sample;
	private SOF sof;
	private Metrics m;
	
	private void lexerState() {
		if (state == STATE_INIT) {
			sof = sample.lexer.parse(buf);
			textPanel.showLexerResult(sof);
			state = STATE_LEXER;
			progressBar.setValue(state);
			progressBar.setString("Lexer done");
		}
	}

	private void linkState() {
		if (state == STATE_LEXER) {
			RecoveryAlgorithm.buildBridges(sof);
			textPanel.showLinkResult();
			state = STATE_LINK;
			progressBar.setValue(state);
			progressBar.setString("Linking done");
		}
	}

	private void recoverState() {
		if (state == STATE_LINK) {
			RecoveryAlgorithm.recover(sof);
			textPanel.showRecoverResult();
			state = STATE_RECOVER;
			progressBar.setValue(state);
			progressBar.setString("Recovery done");
		}
	}

	private void outputState() {
		if (state == STATE_RECOVER) {
			StringBuffer buf = RecoveryHelper.prettyPrint(sof);
			textPanel.showOutputResult(buf.toString());
			state = STATE_OUTPUT;
			progressBar.setValue(state);
			progressBar.setString("Output done");
			RecoveryHelper.printStats(sof, this.buf.toString(), sample.name);
		}
	}
}

